package com.developteam.xnmall.service.impl;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.developteam.xnmall.dao.ProductImgMapper;
import com.developteam.xnmall.dao.ProductMapper;
import com.developteam.xnmall.dao.ProductParamsMapper;
import com.developteam.xnmall.dao.ProductSkuMapper;
import com.developteam.xnmall.entity.*;
import com.developteam.xnmall.service.ProductService;
import com.developteam.xnmall.utils.PageHelper;
import com.developteam.xnmall.vo.ResStatus;
import com.developteam.xnmall.vo.ResultVO;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.io.IOException;
import java.util.*;

@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private ProductImgMapper productImgMapper;
    @Autowired
    private ProductSkuMapper productSkuMapper;
    @Autowired
    private ProductParamsMapper productParamsMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    public ResultVO listRecommendProducts() {
        List<ProductVO> productVOS = productMapper.selectRecommendProducts();
        ResultVO resultVO = new ResultVO(ResStatus.OK, "success", productVOS);
        return resultVO;
    }

    //整个都是查询操作，将传播机制设置为SUPPORTS，表示不需要事务，当被一个事务调用时，也能加入到事务中来
    //【事务传播机制，默认可重复读】，只有查询操作的时候用的是快照读（此时可重复读读到的是历史版本），当有update和delete的时候才去用当前读
    @Transactional(propagation = Propagation.SUPPORTS)
    public ResultVO getProductBasicInfo(String productId) {
        try {
            //一、根据商品id查询redis
            String productsInfo = (String) stringRedisTemplate.boundHashOps("products").get(productId);
            //二、如果redis查询到了商品信息，直接返回给控制器
            if (productsInfo != null) {
                Product product = objectMapper.readValue(productsInfo, Product.class);

                String imgsStr = (String) stringRedisTemplate.boundHashOps("productImgs").get(productId);
                JavaType javaType1 = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, ProductImg.class);//将json字符串转成集合
                List<ProductImg> productImgs = objectMapper.readValue(imgsStr, javaType1);

                String skusStr = (String) stringRedisTemplate.boundHashOps("productSkus").get(productId);
                JavaType javaType2 = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, ProductSku.class);
                List<ProductSku> productSkus = objectMapper.readValue(skusStr, javaType2);

                HashMap<String, Object> basicInfo = new HashMap<>();
                basicInfo.put("product", product);
                basicInfo.put("productImgs", productImgs);
                basicInfo.put("productSkus", productSkus);

                return new ResultVO(ResStatus.OK, "success", basicInfo);
            } else {
                //三、如果redis没有查询到商品信息，就查询到数据库
                //1.商品基本信息
                Example example = new Example(Product.class);
                Example.Criteria criteria = example.createCriteria();
                criteria.andEqualTo("productId", productId);
                criteria.andEqualTo("productStatus", 1);   //状态为1表示上架商品
                List<Product> products = productMapper.selectByExample(example);  //只会找到一个用户
                if (products.size() > 0) {
                    //四、将数据库查询到的数据写入到redis中，为了之后查询
                    Product product = products.get(0);
                    String jsonStr = objectMapper.writeValueAsString(product);
                    stringRedisTemplate.boundHashOps("products").put(productId, jsonStr);

                    //商品存在才查图片和套餐
                    //2.商品图片
                    Example example1 = new Example(ProductImg.class);
                    Example.Criteria criteria1 = example1.createCriteria();
                    criteria1.andEqualTo("itemId", productId);
                    List<ProductImg> productImgs = productImgMapper.selectByExample(example1);
                    stringRedisTemplate.boundHashOps("productImgs").put(productId, objectMapper.writeValueAsString(productImgs));

                    //3.商品套餐
                    Example example2 = new Example(ProductSku.class);
                    Example.Criteria criteria2 = example2.createCriteria();
                    criteria2.andEqualTo("productId", productId);
                    criteria2.andEqualTo("status", 1);
                    List<ProductSku> productSkus = productSkuMapper.selectByExample(example2);
                    stringRedisTemplate.boundHashOps("productSkus").put(productId, objectMapper.writeValueAsString(productSkus));

                    HashMap<String, Object> basicInfo = new HashMap<>();
                    basicInfo.put("product", products.get(0));
                    basicInfo.put("productImgs", productImgs);
                    basicInfo.put("productSkus", productSkus);

                    return new ResultVO(ResStatus.OK, "success", basicInfo);
                }
            }
        } catch (Exception e) {

        }
        return new ResultVO(ResStatus.NO, "fail", null);
    }

    @Override
    public ResultVO getProductParamsById(String productId) {
        Example example = new Example(ProductParams.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("productId", productId);
        List<ProductParams> productParams = productParamsMapper.selectByExample(example);
        if (productParams.size() > 0) {
            return new ResultVO(ResStatus.OK, "success", productParams.get(0));
        } else {
            return new ResultVO(ResStatus.NO, "此商品可能为三无产品", null);
        }
    }

    @Override
    public ResultVO getProductsByCategoryId(int categoryId, int pageNum, int limit) {
        //1.查询分页数据
        int start = (pageNum - 1) * limit;
        List<ProductVO> productVOS = productMapper.selectProductByCategoryId(categoryId, start, limit);
        //2.查询当前类别下的商品的总记录数
        Example example = new Example(Product.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("categoryId", categoryId);
        int count = productMapper.selectCountByExample(example);
        //3.计算总页数
        int pageCount = count % limit == 0 ? count / limit : count / limit + 1;
        //4.封装返回数据
        PageHelper<ProductVO> pageHelper = new PageHelper<>(count, pageCount, productVOS);
        return new ResultVO(ResStatus.OK, "SUCCESS", pageHelper);  //分页查询的data是PageHelper对象
    }

    @Override
    public ResultVO listBrands(int categoryId) {
        List<String> brands = productMapper.selectBrandByCategoryId(categoryId);
        return new ResultVO(ResStatus.OK, "success", brands);
    }

//    @Override
//    public ResultVO searchProduct(String kw, int pageNum, int limit) {
//        //1.查询搜索结果
//        kw = "%" + kw + "%";
//        int start = (pageNum - 1) * limit;
//        List<ProductVO> productVOS = productMapper.selectProductByKeyword(kw, start, limit);
//
//        //2.查询总记录数
//        Example example = new Example(Product.class);
//        Example.Criteria criteria = example.createCriteria();
//        criteria.andLike("productName", kw);
//        int count = productMapper.selectCountByExample(example);
//
//        //3.计算总页数
//        int pageCount = count % limit == 0 ? count / limit : count / limit + 1;
//
//        //4.封装，返回数据
//        PageHelper<ProductVO> pageHelper = new PageHelper<>(count, pageCount, productVOS);
//        ResultVO resultVO = new ResultVO(ResStatus.OK, "SUCCESS", pageHelper);
//        return resultVO;
//    }

    @Override
    public ResultVO searchProduct(String kw, int pageNum, int limit) {
        ResultVO resultVO = null;
        try {
            //从 ES中查询数据
            SearchRequest searchRequest = new SearchRequest("fmmallproductsindex");
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

            //查询条件 (在商品名和套餐中包含都可以)
            searchSourceBuilder.query(QueryBuilders.multiMatchQuery(kw, "productName", "productSkuName"));

            //分页条件
            int start = (pageNum - 1) * limit;
            searchSourceBuilder.from(start);
            searchSourceBuilder.size(limit);

            //高亮显示
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            HighlightBuilder.Field field1 = new HighlightBuilder.Field("productName");
            HighlightBuilder.Field field2 = new HighlightBuilder.Field("productSkuName");
            highlightBuilder.field(field1);
            highlightBuilder.field(field2);
            highlightBuilder.preTags("<label style='color:red'>");
            highlightBuilder.postTags("</label>");
            searchSourceBuilder.highlighter(highlightBuilder);
            searchRequest.source(searchSourceBuilder); //将searchSourceBuilder设置到searchRequest中

            //执行检索
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            //封装查询结果
            SearchHits hits = searchResponse.getHits();
            Iterator<SearchHit> iterator = hits.iterator();
            List<Product4ES> product4ESs = new ArrayList<>();
            while (iterator.hasNext()) {
                SearchHit searchHit = iterator.next();
                Product4ES product4ES = objectMapper.readValue(searchHit.getSourceAsString(), Product4ES.class);
                ///获取高亮字段
                Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
                ///productName
                HighlightField highlightField1 = highlightFields.get("productName");
                if (highlightField1 != null) {
                    String highLightProductName = Arrays.toString(highlightField1.fragments());
                    product4ES.setProductName(highLightProductName);
                }
                product4ESs.add(product4ES);
            }

            int count = (int)hits.getTotalHits().value;  ///获取总记录数

            //计算总页数
            int pageCount = count%limit == 0 ? count/limit : count/limit+1;

            PageHelper<Product4ES> pageHelper = new PageHelper<>(count, pageCount, product4ESs);
            resultVO = new ResultVO(ResStatus.OK, "success", pageHelper);

        } catch (IOException e) {
            e.printStackTrace();
        }
        return resultVO;
    }


    @Override
    public ResultVO listBrands(String kw) {
        kw = "%" + kw + "%";
        List<String> brands = productMapper.selectBrandByKeyword(kw);
        return new ResultVO(ResStatus.OK, "SUCCESS", brands);
    }
}
